home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gdevhl7x.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  30.0 KB  |  1,074 lines

  1. /* Copyright (C) 1997, 2000 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /* $Id: gdevhl7x.c,v 1.3 2000/09/19 19:00:13 lpd Exp $ */
  20. /*
  21.  * Brother HL 720 and 730 driver for Ghostscript
  22.  *
  23.  * Note: for the HL 760, use the HP driver.
  24.  *
  25.  * The original code was borrowed from the
  26.  * HP LaserJet/DeskJet driver for Ghostscript.
  27.  * The code specific to the Brother HL 720 was written by :
  28.  *       Pierre-Olivier Gaillard (pierre.gaillard@hol.fr)
  29.  * Thanks to the documentation kindly provided by :
  30.  *        Richard Thomas <RICHARDT@brother.co.uk>
  31.  *
  32.  * Removal of compression code on 1/17/00 by Ross Martin
  33.  * (ross@ross.interwrx.com, martin@walnut.eas.asu.edu)
  34.  * enables this driver to correctly print tiger.ps on a
  35.  * Brother MFC6550MC Fax Machine.  Change to the Horizontal
  36.  * Offset fixes incorrect page alignment at 300dpi in
  37.  * Landscape mode with a2ps.
  38.  */
  39. #include "gdevprn.h"
  40. /* The following line is used though these printers are not PCL printers*/
  41. /* This is because we want the paper size access function */
  42. /* (The 720 is a simple GDI printer) */
  43. #include "gdevpcl.h"
  44.  
  45. /*
  46.  * You may select a default resolution of  150 (for 730), 300, or
  47.  * 600 DPI in the makefile, or an actual resolution on
  48.  * the gs command line.
  49.  *
  50.  * If the preprocessor symbol A4 is defined, the default paper size is
  51.  * the European A4 size; otherwise it is the U.S. letter size (8.5"x11").
  52.  *
  53.  * You may find the following test page useful in determining the exact
  54.  * margin settings on your printer.  It prints four big arrows which
  55.  * point exactly to the for corners of an A4 sized paper. Of course the
  56.  * arrows cannot appear in full on the paper, and they are truncated by
  57.  * the margins. The margins measured on the testpage must match those
  58.  * in gdevdjet.c.  So the testpage indicates two facts: 1) the page is
  59.  * not printed in the right position 2) the page is truncated too much
  60.  * because the margins are wrong. Setting wrong margins in gdevdjet.c
  61.  * will also move the page, so both facts should be matched with the
  62.  * real world.
  63.  
  64. %!
  65.     newpath 
  66.     0 0 moveto 144 72 lineto 72 144 lineto
  67.     closepath fill stroke 0 0 moveto 144 144 lineto stroke
  68.  
  69.     595.27 841.88 moveto 451.27 769.88 lineto 523.27 697.88 lineto
  70.     closepath fill stroke 595.27 841.88 moveto 451.27 697.88 lineto stroke
  71.  
  72.     0 841.88 moveto 144 769.88 lineto 72 697.88 lineto
  73.     closepath fill stroke 0 841.88 moveto 144 697.88 lineto stroke
  74.  
  75.     595.27 0 moveto 451.27 72 lineto 523.27 144 lineto
  76.     closepath fill stroke 595.27 0 moveto 451.27 144 lineto stroke
  77.  
  78.     /Helvetica findfont
  79.     14 scalefont setfont
  80.     100 600 moveto
  81.     (This is an A4 testpage. The arrows should point exactly to the) show
  82.     100 580 moveto
  83.     (corners and the margins should match those given in gdev*.c) show
  84.     showpage
  85.  
  86.  */
  87.  
  88.  
  89. /* Type definitions */
  90. typedef struct {
  91.   short width;                /* physical width of the paper */
  92.   short height;               /* physical height of the paper */
  93. }                 PaperFormat; /* Rep. of the charateristics of a sheet of paper */
  94.  
  95. typedef unsigned char Byte; /* Rep. of elementary data unit */
  96.  
  97.  
  98.  
  99. /*
  100.  * Definition of a Helper structure to handle a list of commands
  101.  */
  102. typedef struct {
  103.   Byte * data;
  104.   short maxSize;
  105.   short current;
  106.  
  107. } ByteList;
  108.  
  109. /* 
  110.  * Type for representing a summary of the previous lines
  111.  *
  112.  */
  113.  
  114. typedef struct {
  115.   short  previousSize;
  116.   Byte   previousData[1500]; /* Size bigger than any possible line */ 
  117.   short  nbBlankLines;
  118.   short  nbLinesSent;
  119.   short  pageWidth;
  120.   short  pageHeight;
  121.   short  horizontalOffset;
  122.   short  resolution;
  123. } Summary;
  124.  
  125.  
  126.  
  127. /* Constants */
  128.  
  129. /* We need a boolean : true , we got it from gdevprn.h */
  130.  
  131. /* Other constants */
  132. private const int DumpFinished = 0;
  133. private const int DumpContinue = 1;
  134. private const int HL7X0_LENGTH = 5; /* Length of a command to tell the size of the data to be sent to the printer*/
  135. private void  makeCommandsForSequence(Byte     * pSource,
  136.                       short      length,
  137.                       ByteList * pCommandList,
  138.                       short      offset,
  139.                       Byte     * pCommandCount,
  140.                       short      rest);
  141.  
  142. /* Auxiliary Functions */
  143.  
  144.  
  145.  
  146. private int dumpPage(gx_device_printer * pSource,
  147.               Byte              * pLineTmp,
  148.               ByteList          * pCommandList,
  149.               Summary           * pSummary
  150.               );
  151. private void initSummary(Summary * s,short pw, short ph, short resolution);
  152.  
  153. private void resetPreviousData(Summary * s);
  154.  
  155. private void makeFullLine( Byte      * pCurrentLine,
  156.                Byte      * pPreviousLine,
  157.                short       lineWidth,
  158.                ByteList  * commandsList,
  159.                short       horizontalOffset
  160.                );
  161.  
  162.  
  163.  
  164. /*
  165.  * Initialize a list of Bytes structure
  166.  */
  167. private void initByteList(ByteList *list, Byte *array, short maxSize,short initCurrent);
  168. private void addByte(ByteList *list,Byte value );
  169. private void addArray(ByteList *list, Byte *source, short nb);
  170. private void addNBytes(ByteList * list, Byte value, short nb);
  171. private Byte * currentPosition(ByteList * list);
  172. private void addCodedNumber(ByteList * list, short number);
  173. private int isThereEnoughRoom(ByteList * list, short biggest);
  174. private short roomLeft(ByteList * list);
  175. private void dumpToPrinter(ByteList * list,FILE * printStream);
  176.  
  177. /* Real Print function */
  178.  
  179. private int hl7x0_print_page(P5(gx_device_printer *, FILE *, int, int, ByteList *));
  180.  
  181.  
  182.  
  183.  
  184.  
  185.  
  186. /* Define the default, maximum resolutions. */
  187. #ifdef X_DPI
  188. #  define X_DPI2 X_DPI
  189. #else
  190. #  define X_DPI 300
  191. #  define X_DPI2 600
  192. #endif
  193. #ifdef Y_DPI
  194. #  define Y_DPI2 Y_DPI
  195. #else
  196. #  define Y_DPI 300
  197. #  define Y_DPI2 600
  198. #endif
  199.  
  200.  
  201. #define LETTER_WIDTH 5100
  202. #define LEFT_MARGIN  30
  203. /* The following table is not actually used.... */
  204. private const PaperFormat tableOfFormats[] = {
  205.     /*  0 P LETTER */ { 2550, 3300 },
  206.     /*  1 P LEGAL  */ { 2550, 4200 },
  207.     /*  2 P EXEC   */ { 2175, 3150 },
  208.     /*  3 P A4(78) */ { 2480, 3507 },
  209.     /*  4 P B5     */ { 2078, 2953 },
  210.     /*  5 P A5     */ { 1754, 2480 },
  211.     /*  6 P MONARC */ { 1162, 2250 },
  212.     /*  7 P COM10  */ { 1237, 2850 },
  213.     /*  8 P DL     */ { 1299, 2598 },
  214.     /*  9 P C5     */ { 1913, 2704 },
  215.     /* 10 P A4Long */ { 2480, 4783 },
  216.  
  217.     /* 11 L LETTER */ { 3300, 2550 },
  218.     /* 12 L LEGAL  */ { 4200, 2550 },
  219.     /* 13 L EXEC   */ { 3150, 2175 },
  220.     /* 14 L A4     */ { 3507, 2480 },
  221.     /* 15 L B5     */ { 2952, 2078 },
  222.     /* 16 L A5     */ { 2480, 1754 },
  223.     /* 17 L MONARC */ { 2250, 1162 },
  224.     /* 18 L COM10  */ { 2850, 1237 },
  225.     /* 19 L DL     */ { 2598, 1299 },
  226.     /* 20 L C5     */ { 2704, 1913 },
  227.     /* 21 L A4Long */ { 4783, 2480 }
  228. };
  229.  
  230.  
  231. /* Compute the maximum length of a compressed line */
  232. private short MaxLineLength(short resolution){
  233. return (((156 * resolution / 150 ) * 5 )/4) + 8;
  234.  
  235.  
  236. /* Margins are left, bottom, right, top. */
  237. /* Quotation from original gdevdjet.c */
  238. /* from Frans van Hoesel hoesel@rugr86.rug.nl.  */
  239. /* A4 has a left margin of 1/8 inch and at a printing width of
  240.  * 8 inch this give a right margin of 0.143. The 0.09 top margin is
  241.  * not the actual margin - which is 0.07 - but compensates for the
  242.  * inexact paperlength which is set to 117 10ths.
  243.  * Somebody should check for letter sized paper. I left it at 0.07".
  244.  */
  245.  
  246.  
  247. /* The A4 margins are almost good */
  248. /* The one for Letter are those of the gdevdjet.c file... */
  249. #define HL7X0_MARGINS_A4    0.1, 0.15, 0.07, 0.05
  250. #define HL7X0_MARGINS_LETTER 0.275, 0.20, 0.25, 0.07
  251.  
  252.  
  253.  
  254. /* We round up the LINE_SIZE to a multiple of a ulong for faster scanning. */
  255. #define W sizeof(word)
  256.  
  257. /* Printer types */
  258.  
  259. #define HL720    0
  260. #define HL730    0 /* No difference */
  261.  
  262.  
  263.  
  264.  
  265. /* The device descriptors */
  266. private dev_proc_open_device(hl7x0_open);
  267. private dev_proc_close_device(hl7x0_close);
  268. private dev_proc_print_page(hl720_print_page);
  269. private dev_proc_print_page(hl730_print_page);
  270.  
  271.  
  272.  
  273. private const gx_device_procs prn_hl_procs =
  274.   prn_params_procs(hl7x0_open, gdev_prn_output_page, hl7x0_close,
  275.            gdev_prn_get_params, gdev_prn_put_params);
  276.  
  277.  
  278. gx_device_printer far_data gs_hl7x0_device =
  279.   prn_device(prn_hl_procs, "hl7x0",
  280.     DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
  281.     X_DPI, Y_DPI,
  282.     0, 0, 0, 0,        /* margins filled in by hl7x0_open */
  283.     1, hl720_print_page); /* The hl720 and hl730 can both use the same print method */
  284.  
  285.  
  286.  
  287. /* Open the printer, adjusting the margins if necessary. */
  288.  
  289. private int 
  290. hl7x0_open(gx_device *pdev)
  291. {    /* Change the margins if necessary. */
  292.     static const float m_a4[4] = { HL7X0_MARGINS_A4 };
  293.     static const float m_letter[4] = { HL7X0_MARGINS_LETTER };
  294.     const float *m =
  295.       (gdev_pcl_paper_size(pdev) == PAPER_SIZE_A4 ? m_a4 : m_letter);
  296.  
  297.     gx_device_set_margins(pdev, m, true);
  298.     return gdev_prn_open(pdev);
  299. }
  300.  
  301.  
  302. /* The orders sent are those provided in the Brother DOS example */
  303. private int 
  304. hl7x0_close(gx_device *pdev)
  305. {
  306.     gx_device_printer *const ppdev = (gx_device_printer *)pdev;
  307.     int code = gdev_prn_open_printer(pdev, 1);
  308.  
  309.     if (code < 0)
  310.     return code;
  311.     fputs("@N@N@N@N@X", ppdev->file) ;
  312.     return gdev_prn_close_printer(pdev);
  313. }
  314.  
  315. /* ------ Internal routines ------ */
  316.  
  317. /* The HL 720 can compress*/
  318. private int
  319. hl720_print_page(gx_device_printer *pdev, FILE *prn_stream)
  320. {
  321.     Byte prefix[] ={
  322.    0x1B,'%','-','1','2','3','4','5','X'
  323.   ,'@','P','J','L',0x0A                         /* set PJL mode */
  324.   ,'@','P','J','L',' ','E','N','T','E','R',' '
  325.   ,'L','A','N','G','U','A','G','E'
  326.   ,' ','=',' ','H','B','P',0x0A                 /* set GDI Printer mode */
  327.   ,'@','L', 0x0           
  328.    };
  329.     ByteList initCommand;
  330.         int x_dpi = pdev->x_pixels_per_inch;
  331.     initByteList(&initCommand,
  332.              prefix,         /* Array */
  333.              sizeof(prefix), /* Total size */
  334.              sizeof(prefix) - 1); /* Leave one byte free since*/
  335.     /* we need to add the following order at the end */
  336.     addByte(&initCommand, (Byte) ((((600/x_dpi) >> 1) \
  337.                           | (((600/x_dpi) >> 1) << 2)))); 
  338.     /* Put the value of the used resolution into the init string */
  339.     
  340.     return hl7x0_print_page(pdev, prn_stream, HL720, 300,
  341.            &initCommand);
  342. }
  343. /* The HL 730 can compress  */
  344. private int
  345. hl730_print_page(gx_device_printer *pdev, FILE *prn_stream)
  346. {    return hl720_print_page(pdev, prn_stream);
  347. }
  348.  
  349. /* Send the page to the printer.  For speed, compress each scan line, */
  350. /* since computer-to-printer communication time is often a bottleneck. */
  351. private int 
  352. hl7x0_print_page(gx_device_printer *pdev, FILE *printStream, int ptype,
  353.   int dots_per_inch, ByteList *initCommand)
  354. {
  355.     /* UTILE*/
  356.   /* Command for a formFeed (we can't use strings because of the zeroes...)*/
  357.   Byte FormFeed[] = {'@','G',0x00,0x00,0x01,0xFF,'@','F'};
  358.   ByteList formFeedCommand;
  359.   /* Main characteristics of the page */
  360.   int line_size       = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
  361.   int x_dpi = pdev->x_pixels_per_inch;
  362.   /*  int y_dpi = pdev->y_pixels_per_inch; */
  363.   int num_rows = dev_print_scan_lines(pdev);
  364.   int result;
  365.   int sizeOfBuffer   = MaxLineLength(x_dpi) + 30; 
  366.   Byte * storage      = (Byte *) gs_malloc(sizeOfBuffer + line_size,
  367.                        1,
  368.                        "hl7x0_print_page");
  369.     /*    bool dup = pdev->Duplex; */
  370.     /* bool dupset = pdev->Duplex_set >= 0; */
  371.     Summary pageSummary;
  372.     ByteList commandsBuffer;
  373.     initSummary(&pageSummary,
  374.             line_size,
  375.             num_rows,
  376.             x_dpi); 
  377.     if ( storage == 0 )    /* can't allocate working area */
  378.         return_error(gs_error_VMerror);
  379.     initByteList(&commandsBuffer, storage, sizeOfBuffer,0 );
  380.     /* PLUS A MOI */
  381.     if ( pdev->PageCount == 0 )
  382.       {        
  383.         /* Put out init string before first page. */
  384.         dumpToPrinter(initCommand, printStream);        /* send init to printer */
  385.  
  386.     }
  387.  
  388.     do {
  389.       result = dumpPage(pdev,
  390.                 storage + sizeOfBuffer, /* The line buffer is after the dump buffer */
  391.                 &commandsBuffer,
  392.                 &pageSummary);
  393.       dumpToPrinter(&commandsBuffer,printStream);
  394.       
  395.     } while (result == DumpContinue);
  396.  
  397.  
  398.     /* end raster graphics and eject page */
  399.     initByteList(&formFeedCommand,
  400.              FormFeed,          /* Array */
  401.              sizeof(FormFeed),  /* Size in bytes */
  402.              sizeof(FormFeed)); /* First free byte */
  403.     dumpToPrinter(&formFeedCommand, printStream);
  404.         
  405.     /* free temporary storage */
  406.     gs_free((char *)storage, storage_size_words, 1, "hl7X0_print_page");
  407.  
  408.     return 0; /* If we reach this line, it means there was no error */
  409. }
  410.  
  411. /*
  412.  * Useful auxiliary declarations 
  413.  *
  414.  */
  415.  
  416.  
  417. private short stripTrailingBlanks(Byte * line, short length){
  418.   short positionOfFirstZero = length - 1;
  419.   while (positionOfFirstZero > 0) {
  420.     if (line[positionOfFirstZero] != 0) {
  421.       return positionOfFirstZero + 1;
  422.     }
  423.     positionOfFirstZero -- ;
  424.   }
  425.   return 0;
  426. }
  427.  
  428. /*
  429.  * Changed the horizontalOffset function 1/17/00 Ross Martin.
  430.  * ross@ross.interwrx.com or martin@walnut.eas.asu.edu
  431.  *
  432.  * The equation used to muliply pixWidth by resolution/600 
  433.  * also.  This didn't work right at resolution 300; it caused
  434.  * landscape pages produced by a2ps to be half off the
  435.  * page, when they were not at 600dpi or on other
  436.  * devices.  I'm not sure the equation below is exactly
  437.  * correct, but it now looks to be pretty close visually,
  438.  * and works correctly at 600dpi and 300dpi.
  439.  */
  440. private short horizontalOffset(short pixWidth,
  441.                   short pixOffset,
  442.                   short resolution){
  443. return (((LETTER_WIDTH * resolution/600 - pixWidth) + pixOffset * 2) + 7) / 8; 
  444.  
  445.  
  446.  
  447.  
  448. /*
  449.  * First values in a Summary
  450.  */ 
  451. private void initSummary(Summary * s,short pw, short ph, short resolution){
  452.   s->previousSize = -1 ;
  453.   s->nbBlankLines = 1;
  454.   s->nbLinesSent = 0;
  455.   s->pageWidth = pw; /* In Bytes */
  456.   s->pageHeight = ph;
  457.   s->horizontalOffset = horizontalOffset( pw * 8,LEFT_MARGIN, resolution) ;
  458.   s->resolution = resolution;
  459. }
  460.  
  461. /*
  462.  * The previous line was blank, so we need to clean the corresponding array
  463.  */
  464. private void resetPreviousData(Summary * s){
  465.  memset(s->previousData,0,s->pageWidth);
  466. }
  467.  
  468.  
  469. /*
  470.  * dumpPage :
  471.  *
  472.  */
  473. private int dumpPage(gx_device_printer * pSource,
  474.               Byte              * pLineTmp,
  475.               ByteList          * pCommandList,
  476.               Summary           * pSummary
  477.               ){
  478.  
  479.   /* Declarations */
  480.   Byte * pSaveCommandStart; 
  481.   short  lineNB;
  482.   short usefulLength;
  483.   short tmpLength;
  484.   /* Initializations */
  485.   /* Make room for size of commands buffer */
  486.   pSaveCommandStart = currentPosition(pCommandList);  
  487.   addNBytes(pCommandList,0,HL7X0_LENGTH);
  488.   /* pSource += pSummary->nbLinesSent * pSummary->pageWidth;*/
  489.   /* Process all possible Lines */
  490.   for (lineNB = pSummary->nbLinesSent /*ERROR? + nbBlankLines */ ; 
  491.        lineNB < pSummary->pageHeight ; lineNB ++ ) {
  492.     /* Fetch the line and put it into the buffer */
  493.     gdev_prn_copy_scan_lines(pSource,
  494.                  lineNB,
  495.                  pLineTmp,
  496.                  pSummary->pageWidth);
  497.  
  498.     usefulLength =  stripTrailingBlanks(pLineTmp,pSummary->pageWidth);
  499.     if (usefulLength != 0) {
  500.  
  501.       /* The line is not blank */
  502.       /* Get rid of the precedent blank lines */
  503.       if (pSummary->nbBlankLines != 0) {
  504.     if ( isThereEnoughRoom( pCommandList, pSummary->nbBlankLines )   ) {
  505.  
  506.       addNBytes(pCommandList,0xff,pSummary->nbBlankLines);
  507.       pSummary->nbBlankLines = 0;
  508.  
  509.     }
  510.     else {
  511.  
  512.       short availableRoom = roomLeft(pCommandList);
  513.       addNBytes(pCommandList,0xff,availableRoom);
  514.       pSummary->nbBlankLines -= availableRoom;
  515.  
  516.       break ; /* We have no more room */
  517.  
  518.     }
  519.  
  520.     resetPreviousData(pSummary); /* Make sure there are zeroes for the previous line */
  521.     pSummary->previousSize = 0; /* The previous line was empty */
  522.  
  523.       }
  524.  
  525.       /* Deal with the current line */
  526.       if (!isThereEnoughRoom(pCommandList,MaxLineLength(pSummary->resolution))){
  527.     break; /* We can process this line */
  528.       }
  529.  
  530.       if (pSummary->previousSize > usefulLength){
  531.     tmpLength = pSummary->previousSize; 
  532.       }
  533.       else {
  534.     tmpLength = usefulLength;
  535.       }
  536.  
  537.       if (pSummary->previousSize == -1 ) {/* This is the first line */
  538.  
  539.     Byte *save = currentPosition(pCommandList);
  540.     addByte(pCommandList,0); /* One byte for the number of commands */
  541.  
  542.     makeCommandsForSequence(pLineTmp, 
  543.                 tmpLength,
  544.                 pCommandList,
  545.                 pSummary->horizontalOffset,
  546.                 save,
  547.                 0);
  548.       }
  549.       else { /*There is a previous line */
  550.  
  551.     makeFullLine(pLineTmp,
  552.              pSummary->previousData,
  553.              tmpLength,
  554.              pCommandList,
  555.              pSummary->horizontalOffset);
  556.       }
  557.       /* The present line will soon be considered as "previous" */
  558.       pSummary->previousSize = tmpLength;
  559.       /* Update the data representing the line will soon be the "previous line" */ 
  560.       memcpy(pSummary->previousData,pLineTmp,tmpLength);
  561.  
  562.     }
  563.     else { /* the current line is blank */ 
  564.       pSummary->nbBlankLines++;
  565.     }
  566.  
  567.   /* And one more line */
  568.     pSummary->nbLinesSent ++;          
  569.   }
  570.     
  571.   if (pCommandList->current > HL7X0_LENGTH){
  572.     short size = pCommandList->current - HL7X0_LENGTH;
  573.     *(pSaveCommandStart++)  = '@';
  574.     *(pSaveCommandStart++)  = 'G';
  575.     *(pSaveCommandStart++)  = (Byte) (size >> 16);
  576.     *(pSaveCommandStart++)  = (Byte) (size >> 8);
  577.     *(pSaveCommandStart++)  = (Byte) (size);
  578.   }
  579.   else {  /* We only met blank lines and reached the end of the page */
  580.     pCommandList->current = 0;
  581.   }
  582.   if (lineNB == pSummary->pageHeight){
  583.     return DumpFinished;
  584.   }
  585.   else {
  586.     return DumpContinue;
  587.   }
  588. }
  589.          
  590.  
  591. /*
  592.  *  makeFullLine : 
  593.  *  process an arbitrary line for which a former line is available
  594.  *  The line will be split in sequences that are different from the 
  595.  * corresponding ones of the previous line. These sequences will be processed
  596.  * by makeCommandsOfSequence.
  597.  */
  598.  
  599.  
  600.  
  601. private void makeFullLine( Byte      * pCurrentLine,
  602.                Byte      * pPreviousLine,
  603.                short       lineWidth,
  604.                ByteList  * commandsList,
  605.                short       horizontalOffset
  606.                ){
  607.   /* Declarations */
  608.   Byte *pPreviousTmp;
  609.   Byte *pCurrentTmp;
  610.   Byte *pNumberOfCommands;
  611.   int loopCounter;
  612.   short remainingWidth;
  613.   Byte *pStartOfSequence;
  614.   /*****************/
  615.   /* Special cases */
  616.   /*****************/
  617.  
  618.   /* I believe this situation to be impossible */
  619.   if (lineWidth <= 0) {
  620.     addByte(commandsList,0xff);
  621.     return;
  622.   }
  623.  
  624.   /*******************/
  625.   /* Initializations */
  626.   /*******************/
  627.   
  628.   pNumberOfCommands = currentPosition(commandsList); /* Keep a pointer to the number of commands */
  629.   addByte(commandsList,0); /* At the moment there are 0 commands */
  630.   
  631.   pPreviousTmp = pPreviousLine;
  632.   pCurrentTmp = pCurrentLine;  
  633.  
  634.   /* Build vector of differences with a Xor */
  635.  
  636.   for (loopCounter = lineWidth ;  0 < loopCounter ; loopCounter -- )
  637.     *pPreviousTmp++ ^= *pCurrentTmp++;
  638.  
  639.   /* Find sequences that are different from the corresponding (i.e. vertically aligned)
  640.    * one of the previous line. Make commands for them.
  641.    */
  642.  
  643.   pStartOfSequence = pPreviousLine;
  644.   remainingWidth = lineWidth;
  645.  
  646.   while (true) {
  647.  
  648.     /*
  649.      * Disabled line-to-line compression, 1/17/00 Ross Martin
  650.      * ross@ross.interwrx.com and/or martin@walnut.eas.asu.edu
  651.      *
  652.      * The compression here causes problems printing tiger.ps.
  653.      * The problem is vertical streaks.  The printer I'm printing
  654.      * to is a Brother MFC6550MC Fax Machine, which may be
  655.      * slightly different from the hl720 and hl730.  Note that
  656.      * this fax machine does support HP LaserJet 2p emulation,
  657.      * but in order to enable it I believe one needs special
  658.      * setup from a DOS program included with the printer.  Thus,
  659.      * the hl7x0 driver seems a better choice.  In any case,
  660.      * on the MFC6550MC, some files print fine with compression
  661.      * turned on, but others such as tiger.ps print with streaks.
  662.      * disabling the compression fixes the problem, so I haven't
  663.      * looked any further at the cause.  It may be that the
  664.      * compression is correct for the hl720 and hl730, and only
  665.      * different for the MFC6550MC, or it may be that tiger.ps
  666.      * won't print correctly with compression enabled on any
  667.      * of these.  It may be that the problem is only with color
  668.      * and/or grayscale prints.  YMMV.  I don't think it likely
  669.      * that turning off compression will cause problems with
  670.      * other printers, except that they may possibly print slower.
  671.      */
  672.  
  673. #ifdef USE_POSSIBLY_FLAWED_COMPRESSION
  674.     /* Count and skip bytes that are not "new" */
  675.     while (true) {
  676.       if (remainingWidth == 0)  /* There is nothing left to do */
  677.     {
  678.       return;
  679.     }
  680.       if (*pStartOfSequence != 0)
  681.     break;
  682.       pStartOfSequence ++;
  683.       horizontalOffset ++; /* the offset takes count of the bytes that are not "new" */
  684.       --remainingWidth;
  685.     }
  686. #endif
  687.     
  688.     pPreviousTmp = pStartOfSequence + 1; /* The sequence contains at least this byte */
  689.     --remainingWidth; 
  690.     
  691.     /* Find the end of the sequence of "new" bytes */
  692.     
  693. #ifdef USE_POSSIBLY_FLAWED_COMPRESSION
  694.     while (remainingWidth != 0 && *pPreviousTmp != 0) {
  695.       ++pPreviousTmp; /* Enlarge the sequence Of new bytes */
  696.       --remainingWidth;
  697.     }
  698. #else
  699.    pPreviousTmp += remainingWidth;
  700.    remainingWidth = 0;
  701. #endif
  702.  
  703.     makeCommandsForSequence(pCurrentLine + (pStartOfSequence - pPreviousLine),
  704.                  pPreviousTmp - pStartOfSequence,
  705.                  commandsList,
  706.                  horizontalOffset,
  707.                  pNumberOfCommands,
  708.                  remainingWidth);
  709.     if (*pNumberOfCommands == 0xfe   /* If the number of commands has reached the maximum value */
  710.     ||                           /* or */ 
  711.     remainingWidth == 0 )        /* There is nothing left to process */
  712.     {
  713.       return;
  714.     }
  715.  
  716.     pStartOfSequence = pPreviousTmp + 1; /* We go on right after the sequence of "new" bytes */
  717.     horizontalOffset = 1;
  718.     --remainingWidth;
  719.   } /* End of While */
  720.   
  721.   
  722.  
  723.  
  724. } /* End of makeFullLine */
  725.  
  726.  
  727.  
  728. /* 
  729.  *  Declarations of functions that are defined further in the file 
  730.  */
  731. private void makeSequenceWithoutRepeat(
  732.                   Byte     * pSequence,
  733.                   short      lengthOfSequence,
  734.                   ByteList * pCommandList, 
  735.                   short      offset             );
  736.  
  737. private void makeSequenceWithRepeat(
  738.                   Byte     * pSequence,
  739.                   short      lengthOfSequence,
  740.                   ByteList * pCommandList, 
  741.                   short      offset             );
  742.  
  743.  
  744. /*
  745.  * makeCommandsForSequence :
  746.  * Process a sequence of new bytes (i.e. different from the ones on the former line)
  747.  */
  748.  
  749. private void makeCommandsForSequence(Byte     * pSource,
  750.                      short      length,
  751.                      ByteList * pCommandList,
  752.                      short      offset,
  753.                      Byte     * pNumberOfCommands,
  754.                      short      rest)         {
  755.   /* Declarations */
  756.   Byte * pStartOfSequence;
  757.   Byte * pEndOfSequence;
  758.   short  remainingLength = length - 1;
  759.  
  760.   pStartOfSequence = pSource;
  761.   pEndOfSequence = pStartOfSequence + 1;
  762.   /* 
  763.    * Process the whole "new" Sequence that is divided into 
  764.    * repetitive and non-repetitive sequences.
  765.    */ 
  766.   while (true) {
  767.     
  768.     /* If we have already stored too many commands, make one last command with 
  769.      * everything that is left in the line and return. 
  770.      */
  771.     if (*pNumberOfCommands == 0xfd) {
  772.       makeSequenceWithoutRepeat(pStartOfSequence,
  773.             1 + remainingLength + rest,
  774.             pCommandList,
  775.             offset);
  776.       ++*pNumberOfCommands;
  777.       return;
  778.     }
  779.     
  780.     /* Start with a sub-sequence without byte-repetition */
  781.     while (true) {
  782.       /* If we have completed the last subsequence */  
  783.       if (remainingLength == 0) {
  784.     makeSequenceWithoutRepeat(pStartOfSequence,
  785.              pEndOfSequence - pStartOfSequence,
  786.              pCommandList,
  787.              offset);
  788.     ++*pNumberOfCommands;
  789.     return;
  790.       }
  791.       /* If we have discovered a repetition */
  792.       if (*pEndOfSequence == *(pEndOfSequence - 1)) {
  793.     break;
  794.       }
  795.       ++ pEndOfSequence; /* The subsequence is bigger*/
  796.       --remainingLength;
  797.     }
  798.     /* If this is a sequence without repetition */
  799.     if (pStartOfSequence != pEndOfSequence - 1) {
  800.       makeSequenceWithoutRepeat(pStartOfSequence,
  801.                 (pEndOfSequence - 1) - pStartOfSequence,
  802.                 pCommandList,
  803.                 offset);
  804.       ++*pNumberOfCommands;
  805.       offset = 0;
  806.       pStartOfSequence = pEndOfSequence - 1;
  807.       
  808.       /* If we have too many commands */
  809.       if (*pNumberOfCommands == 0xfd) {
  810.     makeSequenceWithoutRepeat(pStartOfSequence,
  811.                   1 + remainingLength + rest,
  812.                   pCommandList,
  813.                   offset);
  814.     ++*pNumberOfCommands;
  815.     return;
  816.       }
  817.     } /* End If */
  818.     
  819.     /* 
  820.      * Process a subsequence that repeats the same byte 
  821.      */
  822.     while (true) {
  823.       /* If there is nothing left to process */
  824.       if (remainingLength == 0) {
  825.     makeSequenceWithRepeat(pStartOfSequence,
  826.                    pEndOfSequence - pStartOfSequence,
  827.                    pCommandList,
  828.                    offset);
  829.     ++*pNumberOfCommands;
  830.     return;             
  831.       }
  832.       /* If we find a different byte */
  833.       if (*pEndOfSequence != *pStartOfSequence){
  834.     break;
  835.       }
  836.       ++pEndOfSequence; /* The subsequence is yet bigger */
  837.       --remainingLength;
  838.     } /* End of While */
  839.       makeSequenceWithRepeat(pStartOfSequence,
  840.                  pEndOfSequence - pStartOfSequence,
  841.                  pCommandList,
  842.                  offset);
  843.       ++*pNumberOfCommands;
  844.       offset = 0;   /* The relative offset between two subsequences is 0 */
  845.       pStartOfSequence = pEndOfSequence ++ ; /* we loop again from the end of this subsequence */
  846.       --remainingLength;
  847.      
  848.   } /* End of While */
  849.   
  850. } /* End makeCommandsForSequence */ 
  851.  
  852.  
  853.  
  854.  
  855.  
  856.  
  857.  
  858.  
  859. /*
  860.  * makeSequenceWithoutRepeat
  861.  */
  862. private void makeSequenceWithoutRepeat(
  863.                   Byte     * pSequence,
  864.                   short      lengthOfSequence,
  865.                   ByteList * pCommandList, 
  866.                   short      offset             ){
  867.   /*
  868.    *   Constant definitions 
  869.    */
  870.   static const short MAX_OFFSET         = 15;
  871.   static const short POSITION_OF_OFFSET = 3;
  872.   static const short MAX_LENGTH         =  7;
  873.   
  874.   Byte tmpFirstByte = 0;
  875.   Byte * pSaveFirstByte;
  876.   short reducedLength = lengthOfSequence - 1; /* Length is alway higher than 1
  877.                          Therefore a reduced value is stored
  878.                          */
  879.   /* Initialization */
  880.  
  881.   pSaveFirstByte = currentPosition(pCommandList);
  882.   addByte( pCommandList, 0 /* Dummy value */);
  883.  
  884.   /* Computations */
  885.  
  886.   if (offset >= MAX_OFFSET) {
  887.     addCodedNumber(pCommandList,offset - MAX_OFFSET);
  888.     tmpFirstByte |= MAX_OFFSET << POSITION_OF_OFFSET;
  889.   }
  890.   else
  891.     tmpFirstByte |= offset << POSITION_OF_OFFSET;
  892.  
  893.   if (reducedLength >= MAX_LENGTH) {
  894.     addCodedNumber(pCommandList,reducedLength - MAX_LENGTH);
  895.     tmpFirstByte |= MAX_LENGTH ;
  896.   }
  897.   else
  898.     tmpFirstByte |= reducedLength ;
  899.   /* Add a copy of the source sequence */
  900.   
  901.   addArray(pCommandList, pSequence, lengthOfSequence);
  902.  
  903.   /* Store the computed value of the first byte */
  904.  
  905.   *pSaveFirstByte = tmpFirstByte;
  906.  
  907.   return ;
  908. } /* End of makeSequenceWithoutRepeat */
  909.  
  910.  
  911.  
  912. /*
  913.  * makeSequenceWithRepeat
  914.  */
  915. private void makeSequenceWithRepeat(
  916.                   Byte     * pSequence,
  917.                   short      lengthOfSequence,
  918.                   ByteList * pCommandList, 
  919.                   short      offset             ){
  920.   /*
  921.    *   Constant definitions 
  922.    */
  923.   static const short MAX_OFFSET         = 3;
  924.   static const short POSITION_OF_OFFSET = 5;
  925.   static const short MAX_LENGTH         =  31;
  926.   
  927.   Byte tmpFirstByte = 0x80; 
  928.   Byte * pSaveFirstByte;
  929.   short reducedLength = lengthOfSequence - 2; /* Length is always higher than 2
  930.                          Therefore a reduced value is stored
  931.                          */
  932.   /* Initialization */
  933.  
  934.   pSaveFirstByte = currentPosition(pCommandList);
  935.   addByte( pCommandList, 0 /* Dummy value */);
  936.  
  937.   /* Computations */
  938.  
  939.   if (offset >= MAX_OFFSET) {
  940.     addCodedNumber(pCommandList, offset - MAX_OFFSET);
  941.     tmpFirstByte |= MAX_OFFSET << POSITION_OF_OFFSET;
  942.   }
  943.   else
  944.     tmpFirstByte |= offset << POSITION_OF_OFFSET;
  945.  
  946.   if (reducedLength >= MAX_LENGTH) {
  947.     addCodedNumber(pCommandList,reducedLength - MAX_LENGTH);
  948.     tmpFirstByte |= MAX_LENGTH ;
  949.   }
  950.   else
  951.     tmpFirstByte |= reducedLength ;
  952.   /* Add a copy the byte that is repeated throughout the sequence */
  953.   
  954.   addByte(pCommandList, *pSequence );
  955.  
  956.   /* Store the computed value of the first byte */
  957.  
  958.   *pSaveFirstByte = tmpFirstByte;
  959.  
  960.   return ;
  961. } /* End of makeSequenceWithRepeat*/
  962.  
  963.  
  964.  
  965.  
  966. /*
  967.  * Initialize a list of Bytes structure
  968.  */
  969. private void initByteList(ByteList *list, Byte *array, short maxSize, short initCurrent) {
  970.   list->current = initCurrent;
  971.   list->maxSize = maxSize;
  972.   list->data = array;
  973. }
  974.  
  975. /*
  976.  * Add a Byte to a list of Bytes
  977.  */
  978. private void addByte(ByteList *list,Byte value ) {
  979.  if (list->current < list->maxSize)
  980.   list->data[list->current++] = value;
  981.  else
  982.    fprintf(stderr,"Could not add byte to command\n");
  983. }
  984.  
  985.  
  986. /*
  987.  * Add a copy of an array to a list of Bytes
  988.  */
  989.  
  990. private void addArray(ByteList *list, Byte *source, short nb){
  991.   if (list->current <= list->maxSize - nb)
  992.   {
  993.     memcpy(list->data + list->current, source , (size_t) nb);
  994.     list->current += nb;
  995.   }
  996.   else 
  997.     fprintf(stderr,"Could not add byte array to command\n");
  998. }
  999.  
  1000.  
  1001. /* 
  1002.  * Add N bytes to a list of Bytes
  1003.  */
  1004.  
  1005. private void addNBytes(ByteList * list, Byte value, short nb){
  1006.   int i;
  1007.   if (list->current <= list->maxSize - nb)
  1008.   {
  1009.     for (i = list->current ; i < (list->current + nb) ; i++)
  1010.       {
  1011.     list->data[i] = value;
  1012.       }
  1013.     list->current += nb;
  1014.   }
  1015.   else 
  1016.     fprintf(stderr,"Could not add %d bytes to command\n",nb);
  1017. }
  1018.  
  1019. /*
  1020.  * Get pointer to the current byte
  1021.  */
  1022. private Byte * currentPosition(ByteList * list) {
  1023.   return &(list->data[list->current]);
  1024. }
  1025.  
  1026. /*
  1027.  * add a number coded in the following way :
  1028.  * q bytes with 0xff value
  1029.  * 1 byte with r value
  1030.  * where q is the quotient of the number divided by 0xff and r is the
  1031.  * remainder.
  1032.  */
  1033. private void addCodedNumber(ByteList * list, short number){
  1034.  short q = number / 0xff;
  1035.  short r = number % 0xff;
  1036.  
  1037.  addNBytes(list, 0xff, q);
  1038.  addByte(list,r);
  1039.  
  1040. }
  1041.  
  1042. /*
  1043.  * See if there is enough room for a set of commands of size biggest
  1044.  *
  1045.  */
  1046.  
  1047. private int isThereEnoughRoom(ByteList * list, short biggest){
  1048.   return ((list->maxSize-list->current) >= biggest);
  1049. }
  1050. /*
  1051.  * Tell how much room is left 
  1052.  */
  1053. private short roomLeft(ByteList * list){
  1054.   return list->maxSize - list->current;
  1055. }
  1056. /*
  1057.  * Dump all commands to the printer and reset the structure
  1058.  *
  1059.  */
  1060. private void dumpToPrinter(ByteList * list,FILE * printStream){
  1061.   short loopCounter;
  1062.   /* Actual dump */
  1063.   /* Please note that current is the first empty byte */
  1064.   for (loopCounter = 0; loopCounter < list->current; loopCounter++)
  1065.     {
  1066.       fputc(list->data[loopCounter],printStream);
  1067.     }
  1068.  
  1069.   /* Reset of the ByteList */
  1070.   list->current = 0;
  1071. }
  1072.